package com.mapler.service;

import com.mapler.model.AdModel;
import com.mapler.model.SModel;
import com.mapler.model.UAModel;
import com.mapler.utility.HotMailHelper;
import com.mapler.utility.HttpHelper;
import com.mapler.utility.IConstant;
import com.mapler.utility.Util;
import com.mapler.utility.W4MUtil;
import java.net.URL;
import java.net.URLDecoder;
import java.util.*;
import javax.mail.*;
import javax.mail.Flags.Flag;
import javax.mail.search.FlagTerm;
import org.apache.log4j.Logger;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Node;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;

public class MailRunner implements Runnable {

    Folder inbox;
    private SModel sModel;
    private static Logger log = Logger.getLogger(MailRunner.class);
    private INotifier iNotifier;
    UAModel uam;
    private HotMailHelper hotMailHelper;
    private AdModel am;

    public MailRunner(INotifier iNotifier, SModel sModel, UAModel uam) {
        this.sModel = sModel;
        this.iNotifier = iNotifier;
        this.uam = uam;
    }

    public MailRunner(INotifier iNotifier, SModel sModel, UAModel uam, AdModel am) {
        this.sModel = sModel;
        this.iNotifier = iNotifier;
        this.uam = uam;
        this.am = am;
    }

    @Override
    public void run() {
        try {
        } catch (Throwable ex) {
            ex.printStackTrace();
            log.debug("run:: Error causes " + ex);
        }
    }

    public void readEmail(WebDriver driver) {
        try {
            uam.setMailFound(false);

        } catch (Throwable ex) {
            iNotifier.notify("mailReader:: error on reading email:" + ex);
            log.debug("mailReader:: error on reading email:" + ex);
        }
    }

    public void checkEmail(WebDriver driver) {
        try {
            uam.setMailFound(false);
            if (sModel.isWebMail()) {
                this.readWebGmail(driver);
            } else {
                this.readMail(driver);
            }

            if (!uam.isMailFound()) {
                iNotifier.notify("Waiting for again email check.");
                Util.wait(Integer.parseInt(sModel.getMaxWaitTime()));
                iNotifier.notify("Going to check email again.");
                if (sModel.isWebMail()) {
                    this.readWebGmail(driver);
                } else {
                    this.readMail(driver);
                }
            }
        } catch (Throwable ex) {
            iNotifier.notify("mailReader:: error on reading email:" + ex);
            log.debug("mailReader:: error on reading email:" + ex);
        }
    }

    public synchronized void readMail(WebDriver driver) {
        try {
            /* Set the mail properties */
            iNotifier.notify("Going to read email inbox");

            String email = uam.getEmail();
            String password = uam.getEmailPassword();
            if (sModel.getUseFWlink().equals("1")) {
                email = uam.getForwardEmail();
                password = uam.getForwardEmailPass();
            }

            if (email.contains("+")) {
                String[] ee = email.split("\\+");
                if (email.contains("@gmail.com")) {
                    email = ee[0] + email.split("@")[1];
                }
            }

            if (email == null || email.isEmpty()) {
                iNotifier.notify("Email address is empty.");
                log.debug("run:: Email address is empty. ");
                return;
            }

            if (password == null || password.isEmpty()) {
                iNotifier.notify("Email password is empty.");
                log.debug("run:: Email password is empty. ");
                return;
            }

            Properties props = System.getProperties();
            props.setProperty("mail.store.protocol", "imaps");

            /* Create the session and get the store for read the mail. */
            iNotifier.notify("Going to connect mail server");
            Session session = Session.getDefaultInstance(props, null);
            Store store = session.getStore("imaps");

            if (email.contains("@gmail")) {
                store.connect("imap.gmail.com", email, password);
            } else if (email.contains("@yahoo")) {
                store.connect("imap.mail.yahoo.com", email, password);
            }

            /* Mention the folder name which you want to read. */
            inbox = store.getFolder("Inbox");
            int unReadMCount = inbox.getUnreadMessageCount();
            iNotifier.notify("No of Unread Messages : " + unReadMCount);
            if (unReadMCount == 0) {
                return;
            }
            /* Open the inbox using store. */
            inbox.open(Folder.READ_ONLY);
            //inbox.open(Folder.READ_WRITE);
            /* Get the messages which is unread in the Inbox */
            Message messages[] = inbox.search(new FlagTerm(new Flags(Flag.SEEN), false));
            /* Use a suitable FetchProfile */
            FetchProfile fp = new FetchProfile();
            fp.add(FetchProfile.Item.ENVELOPE);
            fp.add(FetchProfile.Item.CONTENT_INFO);
            inbox.fetch(messages, fp);
            try {
                for (int i = 0; i < messages.length; i++) {
                    Message message = messages[i];
                    this.parseMessage(message, driver);
                }
                //inbox.setFlags(messages, new Flags(Flags.Flag.SEEN), true);
                inbox.close(true);
                store.close();
            } catch (Throwable ex) {
                log.debug("readMail :: Exception arise at the time of read mail " + ex);
                iNotifier.notify("Exception arise at the time of read mail");
                ex.printStackTrace();
            }
        } catch (NoSuchProviderException ex) {
            log.debug("readMail :: Error on NoSuchProviderException " + ex);
            iNotifier.notify("Exception arise at the time of read mail");
            ex.printStackTrace();
        } catch (MessagingException ex) {
            log.debug("readMail :: Error on MessagingException " + ex);
            iNotifier.notify("Exception arise at the time of read mail");
            ex.printStackTrace();
        } catch (Throwable ex) {
            log.debug("readMail :: Error on MessagingException " + ex);
            iNotifier.notify("Exception arise at the time of read mail");
            ex.printStackTrace();
        }
    }

    public void parseMessage(Message message, WebDriver driver) throws Exception {
        try {
            String sub = message.getSubject();
            if (!sub.contains("POST/EDIT/DELETE") || (am != null && !sub.contains(am.getTitle()))) {
                return;
            }
            String contentType = message.getContentType();
            System.out.println("Content Type : " + contentType);
            if (message.getContent() instanceof Multipart) {
                Multipart mp = (Multipart) message.getContent();
                int count = mp.getCount();
                for (int j = 0; j < count; j++) {
                    String s = mp.getBodyPart(j).getContent().toString();
                    String lines[] = s.split("\\r?\\n");
                    for (int k = 0; k < lines.length; k++) {
                        if (lines[k].contains("https://post.craigslist.org") && lines[k].startsWith("https")) {
                            log.debug("readMail :: Posting link found " + lines[k]);
                            iNotifier.notify("Posting link found now going to click on this link");
                            this.update(lines[k], driver);
                            uam.setMailFound(true);
                            break;
                        }
                    }
                }
            } else {
                String html = message.getContent().toString();
                org.jsoup.nodes.Document doc = Jsoup.parse(html);
                Elements links = doc.select("a[href]");
                for (Element link : links) {
                    if (link.text().contains("https://post.craigslist.org")) {
                        log.debug("readWebGmail :: Posting link found " + link.text());
                        iNotifier.notify("Posting link found now going to click on this link ");
                        this.update(link.text(), driver);
                        uam.setMailFound(true);
                        break;
                    }

                }
            }

        } catch (Throwable ex) {
            log.debug("readAllMessages :: Error " + ex);
            iNotifier.notify("Exception arise at the time of parsing email.");
            ex.printStackTrace();
        }
    }

    private void update(String link, WebDriver driver) {
        try {
            driver.get(link);
            List<WebElement> elements = driver.findElements(By.tagName("button"));
            for (WebElement elementLink : elements) {
                if (elementLink.getText() != null
                        && elementLink.getText().trim().contains(
                        "ACCEPT the terms of use")) {
                    elementLink.click();
                    break;
                }
            }

            elements = driver.findElements(By.tagName("li"));
            for (WebElement pelement : elements) {
                if (pelement.getText().contains(
                        "Your posting can be seen at")) {
                    elements = pelement.findElements(By.tagName("a"));
                    for (WebElement elementLink : elements) {
                        if (elementLink.getText().contains(
                                "craigslist.org")) {
                            Util.addPostInfo(iNotifier, sModel, elementLink.getText());
                            break;
                        }
                    }
                    break;
                }
            }
        } catch (Throwable ex) {
            log.debug("update :: Error " + ex);
            iNotifier.notify("Exception arise at the time of link posting. " + ex.getMessage());
            ex.printStackTrace();
        }
    }

    public void readWebGmail(WebDriver driver) {
        try {
            String email = uam.getEmail();
            String password = uam.getEmailPassword();
            if (sModel.getUseFWlink().equals("1")) {
                email = uam.getForwardEmail();
                password = uam.getForwardEmailPass();
            }

            if (email.contains("+")) {
                String[] ee = email.split("\\+");
                email = ee[0] + "@gmail.com";
            }

            if (email == null || email.isEmpty()) {
                iNotifier.notify("Email address is empty.");
                log.debug("run:: Email address is empty. ");
                return;
            }

            if (password == null || password.isEmpty()) {
                iNotifier.notify("Email password is empty.");
                log.debug("run:: Email password is empty. ");
                return;
            }

            StringBuilder param = new StringBuilder();
            param.append("username=").append(sModel.getUsername());
            param.append("&password=").append(sModel.getPassword());
            param.append("&email=").append(email);
            param.append("&epassword=").append(password);
            param.append("&eSubject=").append(am.getTitle());

            String uri = "http://" + IConstant.WEBHOSTNAME + "/maplew/ReaderWS";
            String response = HttpHelper.post(new URL(uri), param.toString());

            Document document = DocumentHelper.parseText(response);
            String errorCode = document.valueOf("Response/errorcode");
            String msg = document.valueOf("Response/message");
            if (!errorCode.equalsIgnoreCase("000")) {
                String isLink = document.valueOf("Response/links/mailfound");
                if (isLink.equals("0")) {
                    iNotifier.notify("Posting link not found");
                    return;
                }
                List<Node> list = document.selectNodes("/Response/links/link");
                int count = 1;
                for (Node node : list) {
                    String link = node.getText();
                    log.debug("readWebGmail :: Posting link found " + link);
                    iNotifier.notify("Posting link found now going to click on this link [" + count + "]");
                    this.updateLink(driver, URLDecoder.decode(link, "UTF-8"));
                    uam.setMailFound(true);
                    count++;
                }
            } else {
                iNotifier.notify("" + msg);
            }
        } catch (Throwable ex) {
            log.debug("updateWorking: Error " + ex);
        }
    }

    private void updateLink(WebDriver driver, String link) {
        try {
            driver.get(link);
            List<WebElement> elements = driver.findElements(By.tagName("button"));
            for (WebElement elementLink : elements) {
                if (elementLink.getAttribute("value") != null
                        && elementLink.getAttribute("value").contains(
                        "ACCEPT the terms of")) {
                    elementLink.submit();
                    break;
                }
            }
            
            boolean postdone = false;
            elements = driver.findElements(By.tagName("li"));
            for (WebElement pelement : elements) {
                if (pelement.getText().contains(
                        "Your posting can be seen at")) {
                    elements = pelement.findElements(By.tagName("a"));
                    for (WebElement elementLink : elements) {
                        if (elementLink.getText().contains(
                                "craigslist.org")) {
                            Util.addPostInfo(iNotifier, sModel, elementLink.getText());
                            postdone = true;
                            break;
                        }
                    }
                    break;
                }
            }
            
            if(postdone){
                W4MUtil.clickReNewLink(driver, sModel, iNotifier);
            }
            
        } catch (Throwable ex) {
            log.debug("update :: Error " + ex);
            iNotifier.notify("Exception arise at the time of link posting. " + ex.getMessage());
            ex.printStackTrace();
        } finally {
        }
    }

    public void checkNGFXEmail(WebDriver driver) {
        try {
            String email = uam.getEmail();
            if (sModel.getUseFWlink().equals("1")) {
                email = uam.getForwardEmail();
            }
            if (!email.contains("@")) {
                iNotifier.notify("Email address is not valid.");
                log.debug("Emal address is not valid.");
                return;
            }
            uam.setMailFound(false);
            String[] ee = email.split("@");
            if (ee[1].equals("gmail.com")) {
                iNotifier.notify("Gmail found going to read gmail.");
                if (sModel.isWebMail()) {
                    this.readNGFXWebGmail(driver);
                } else {
                    this.readNGFXGmail(driver);
                }

                if (!uam.isMailFound()) {
                    iNotifier.notify("Waiting for again email check.");
                    Util.wait(Integer.parseInt(sModel.getMaxWaitTime()));
                    iNotifier.notify("Going to check email again.");
                    if (sModel.isWebMail()) {
                        this.readNGFXWebGmail(driver);
                    } else {
                        this.readNGFXGmail(driver);
                    }
                }
            } else if (ee[1].equals("hotmail.com")) {
                iNotifier.notify("Hotmail found going to read hotmail.");
                if (sModel.isWebMail()) {
                    this.readNGFXWebGmail(driver);
                } else {
                    this.getHotMailHelper().readNGFXHotmail(driver, sModel, uam, iNotifier);
                }

                if (!uam.isMailFound()) {
                    iNotifier.notify("Waiting for again email check.");
                    Util.wait(Integer.parseInt(sModel.getMaxWaitTime()));
                    iNotifier.notify("Going to check email again.");
                    if (sModel.isWebMail()) {
                        this.readNGFXWebGmail(driver);
                    } else {
                        this.getHotMailHelper().readNGFXHotmail(driver, sModel, uam, iNotifier);
                    }
                }
            }


        } catch (Throwable ex) {
            iNotifier.notify("mailReader:: error on reading email:" + ex);
            log.debug("mailReader:: error on reading email:" + ex);
            ex.printStackTrace();
        }
    }

    public void readNGFXWebGmail(WebDriver driver) {
        try {
            String email = uam.getEmail();
            String password = uam.getEmailPassword();
            if (sModel.getUseFWlink().equals("1")) {
                email = uam.getForwardEmail();
                password = uam.getForwardEmailPass();
            }

            if (email.contains("+")) {
                String[] ee = email.split("\\+");
                email = ee[0] + "@gmail.com";
            }

            if (email == null || email.isEmpty()) {
                iNotifier.notify("Email address is empty.");
                log.debug("run:: Email address is empty. ");
                return;
            }

            if (password == null || password.isEmpty()) {
                iNotifier.notify("Email password is empty.");
                log.debug("run:: Email password is empty. ");
                return;
            }

            StringBuilder param = new StringBuilder();
            param.append("username=").append(sModel.getUsername());
            param.append("&password=").append(sModel.getPassword());
            param.append("&email=").append(email);
            param.append("&epassword=").append(password);

            String uri = "http://" + IConstant.WEBHOSTNAME + "/maplew/ReaderNGFXWS";
            String response = HttpHelper.post(new URL(uri), param.toString());

            Document document = DocumentHelper.parseText(response);
            String errorCode = document.valueOf("Response/errorcode");
            String msg = document.valueOf("Response/message");
            if (!errorCode.equalsIgnoreCase("000")) {
                String isLink = document.valueOf("Response/links/mailfound");
                if (isLink.equals("0")) {
                    iNotifier.notify("Posting link not found");
                    return;
                }
                List<Node> list = document.selectNodes("/Response/links/link");
                int count = 1;
                for (Node node : list) {
                    String link = node.getText();
                    log.debug("readWebGmail :: Posting link found " + link);
                    iNotifier.notify("Posting link found now going to click on this link [" + count + "]");
                    driver.get(URLDecoder.decode(link, "UTF-8"));
                    uam.setMailFound(true);
                    count++;
                }
            } else {
                iNotifier.notify("" + msg);
            }
        } catch (Throwable ex) {
            log.debug("updateWorking: Error " + ex);
        }
    }

    public synchronized void readNGFXGmail(WebDriver driver) {
        try {
            /* Set the mail properties */
            iNotifier.notify("Going to read email inbox");

            String email = uam.getEmail();
            String password = uam.getEmailPassword();
            if (sModel.getUseFWlink().equals("1")) {
                email = uam.getForwardEmail();
                password = uam.getForwardEmailPass();
            }

            if (email.contains("+")) {
                String[] ee = email.split("\\+");
                email = ee[0] + "@gmail.com";
            }

            if (email == null || email.isEmpty()) {
                iNotifier.notify("Email address is empty.");
                log.debug("run:: Email address is empty. ");
                return;
            }

            if (password == null || password.isEmpty()) {
                iNotifier.notify("Email password is empty.");
                log.debug("run:: Email password is empty. ");
                return;
            }

            Properties props = System.getProperties();
            props.setProperty("mail.store.protocol", "imaps");

            /* Create the session and get the store for read the mail. */
            iNotifier.notify("Going to connect mail server");
            Session session = Session.getDefaultInstance(props, null);
            Store store = session.getStore("imaps");
            store.connect("imap.gmail.com", email, password);

            /* Mention the folder name which you want to read. */
            inbox = store.getFolder("Inbox");
            int unReadMCount = inbox.getUnreadMessageCount();
            iNotifier.notify("No of Unread Messages : " + unReadMCount);
            if (unReadMCount == 0) {
                return;
            }
            /* Open the inbox using store. */
            //inbox.open(Folder.READ_ONLY);
            inbox.open(Folder.READ_WRITE);
            /* Get the messages which is unread in the Inbox */
            Message messages[] = inbox.search(new FlagTerm(new Flags(Flag.SEEN), false));
            /* Use a suitable FetchProfile */
            FetchProfile fp = new FetchProfile();
            fp.add(FetchProfile.Item.ENVELOPE);
            fp.add(FetchProfile.Item.CONTENT_INFO);
            inbox.fetch(messages, fp);
            try {
                for (int i = 0; i < messages.length; i++) {
                    Message message = messages[i];
                    this.parseNGFXMessage(driver, message);
                }
                inbox.setFlags(messages, new Flags(Flags.Flag.SEEN), true);
                inbox.close(true);
                store.close();
            } catch (Throwable ex) {
                log.debug("readMail :: Exception arise at the time of read mail " + ex);
                iNotifier.notify("Exception arise at the time of read mail");
                ex.printStackTrace();
            }
        } catch (NoSuchProviderException ex) {
            log.debug("readMail :: Error on NoSuchProviderException " + ex);
            iNotifier.notify("Exception arise at the time of read mail");
            ex.printStackTrace();
        } catch (MessagingException ex) {
            log.debug("readMail :: Error on MessagingException " + ex);
            iNotifier.notify("Exception arise at the time of read mail");
            ex.printStackTrace();
        } catch (Throwable ex) {
            log.debug("readMail :: Error on MessagingException " + ex);
            iNotifier.notify("Exception arise at the time of read mail");
            ex.printStackTrace();
        }
    }

    public void parseNGFXMessage(WebDriver driver, Message message) throws Exception {
        try {
            String sub = message.getSubject();
            if (!sub.contains("Action Required to Activate Membership for Forex")) {
                return;
            }
            String contentType = message.getContentType();
            System.out.println("Content Type : " + contentType);
            if (message.getContent() instanceof Multipart) {
                Multipart mp = (Multipart) message.getContent();
                int count = mp.getCount();
                for (int j = 0; j < count; j++) {
                    String s = mp.getBodyPart(j).getContent().toString();
                    String lines[] = s.split("\\r?\\n");
                    for (int k = 0; k < lines.length; k++) {
                        if (lines[k].contains("http://nigeria-forex.com/register.php") && lines[k].startsWith("http")) {
                            log.debug("readWebGmail :: Posting link found " + lines[k]);
                            iNotifier.notify("Posting link found now going to click on this link [" + count + "]");
                            driver.get(lines[k]);
                            uam.setMailFound(true);
                            break;
                        }
                    }
                }
            } else {
                String html = message.getContent().toString();
                org.jsoup.nodes.Document doc = Jsoup.parse(html);
                Elements links = doc.select("a[href]");
                for (Element link : links) {
                    if (link.text().contains("http://nigeria-forex.com/register.php")) {
                        log.debug("readWebGmail :: Posting link found " + link.text());
                        iNotifier.notify("Posting link found now going to click on this link ");
                        driver.get(link.text());
                        uam.setMailFound(true);
                        break;
                    }

                }
            }

        } catch (Throwable ex) {
            log.debug("readAllMessages :: Error " + ex);
            iNotifier.notify("Exception arise at the time of parsing email.");
            ex.printStackTrace();
        }
    }

    public HotMailHelper getHotMailHelper() {
        if (hotMailHelper == null) {
            hotMailHelper = new HotMailHelper();
        }
        return hotMailHelper;
    }

    public void setHotMailHelper(HotMailHelper hotMailHelper) {
        this.hotMailHelper = hotMailHelper;
    }
}
